package roborally;

import Exceptions.ElementPlacementError;
import Exceptions.IllegalCoordinateException;
import Exceptions.ShootException;
import Exceptions.TerminationError;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Model;
import be.kuleuven.cs.som.annotate.Raw;

/**@author Jef Keijers/Bachelor of Science: Informatics
 * @version 1.0
 * 
 *  @invar  The position of each element must be a valid position.
 *        	| canHaveAsPosition(this.getPosition())
 *  @invar 	The board of each element must be a valid board.
 *  		| isProperBoard(board);
 *        
 * 
 */
public abstract class Element extends Terminatable {

	/**
	 * @post 
	 * 			| this.board == null
	 * @post 
	 * 			| this.position == null
	 */
	@Model @Raw
	protected Element() {
		this.board=null;
		this.position=null;
	}

	@Basic
	public Board getBoard(){
		return board;
	}

	/**
	 * @param 	board
	 * @throws 	ElementPlacementError 
	 * 			if (!(isProperBoard(board))) 
	 * @post 	
	 * 			| new.getBoard() == board
	 */
	public void setBoard(Board board) throws ElementPlacementError {
		if(isProperBoard(board))
			this.board=board;
		else
			throw new ElementPlacementError(); 
	}

	@Basic
	public Position getPosition(){		
		return position;
	}

	/**
	 * @param 	position
	 * @post 
	 * 			| new.getPosition() == position
	 * @throws 	IllegalArgumentException
	 * 			| if (!(isProperPosition(position))) 
	 */
	public void setPosition(Position position) throws IllegalCoordinateException {
		if(isProperPosition(position))
			this.position=position;
		else
			throw new IllegalCoordinateException();
	}
	
	@Basic
	public double getMaxEnergyToRemoveWhenShot() {
		return MaxEnergyToRemoveWhenShot;
	}
	
	@Basic
	public double getEnergyToAddWhenShot() {
		return EnergyToAddWhenShot;
	}
	
	@Basic
	public Energy getEnergy() {
		return energy;
	}
	
	/**
	 * @param	energy
	 * @post	
	 * 			|new.energy == energy
	 */
	public void setEnergy(Energy energy) {
		this.energy=energy;
	}
	
	/**
	 * @param board
	 * @return	
	 * 			|if (board!=null) result ==  true
	 */
	private boolean isProperBoard(Board board) {
		return board != null;
	}

	/**
	 * @param 	position
	 * @return	
	 * 			|if((position != null) && (position.getX()>= 0) && (position.getX() < board.getWidth() && (position.getY()>= 0) 
	 *				&& (position.getY()< board.getHeight()))) result == true
	 */
	private boolean isProperPosition(Position position) {
		if((position != null) && (position.getX()>= 0) && (position.getX() < board.getWidth() && (position.getY()>= 0) 
			&& (position.getY()< board.getHeight())))
				return true;
		return false;	

	}
	
	/**
	 * @param other
	 */
	public boolean canSharePositionWith(Element other) {
		if (other instanceof Wall) {
			return false;
		}else if (this instanceof Wall) {
			return false;
		} else if ((this instanceof Robot) && (other instanceof Robot)) {
			return false;
		}
		return true;
	}

	private Board board;
	private Position position;
	private Energy energy;	
	private double EnergyToAddWhenShot=500;
	private double MaxEnergyToRemoveWhenShot=4000;

	/**
	 * @post 
	 * 			| new.getBoard() == null
	 * @post 
	 * 			| new.getPostion() == null
	 * @post 
	 * 			| new.isTerminated() == true
	 */
	@Raw
	public void terminate() {
		this.board=null;
		this.position=null;		
		this.setIsTerminatedToTrue();	
	}
	
	@Raw
	public abstract void handleShot() throws TerminationError, IllegalCoordinateException, ShootException;

}
